/*
 * Copyright (C) 2010, Funcom AS, All Rights Reserved
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 *  @authors
 *  Svein Gunnar Larsen <sveingunnarlarsen@gmail.com>
 *  Erik Thune Lund <culex.eriklund@gmail.com>
 *  Michel Krohn-Dale <kronicz@gmail.com>
 */

package com.funcom.peeler.properties;

import com.funcom.peeler.UpdateCont;
import com.funcom.peeler.WorkBench;
import com.funcom.peeler.peelable.PeelComponent;

import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.lang.reflect.InvocationTargetException;
import java.util.*;
import java.util.Queue;

import static com.funcom.peeler.UpdateCont.get;

public class PropertiesFrame extends JFrame {

    private JPanel main_panel;

    // Objects for default text fields class.
    private JLabel elementField;
    private JLabel parentField;
    private JTextField nameTextField;
    private JTextField styleClassTextField;
    private JTextField size_XTextField;
    private JTextField size_YTextField;
    private JTextField posXTextField;
    private JTextField posYTextField;

    // Objects for stateBoxes class.
    private JCheckBox defaultCheckBox;
    private JCheckBox hoverCheckBox;
    private JCheckBox disableCheckBox;
    private JCheckBox downCheckBox;
    private JCheckBox selectedCheckBox;
    private JCheckBox deSelectedCheckBox;

    // Objects for the text setting class.
    private JTextField setTextField;
    private JTextField setLocalizedText;
    private JComboBox localeChooser;
    private JTextField leftTextField;
    private JTextField rightTextField;
    private JTextField topTextField;
    private JTextField bottomTextField;
    private JPanel pnlTextColor;
    private JRadioButton leftRadioAlignment;
    private JRadioButton rightRadioAlignment;
    private JRadioButton topRadioAlignment;
    private JRadioButton bottomRadioAlignment;
    private JRadioButton centerRadioAlignment;
    private JRadioButton centerRadioVerAlignment;

    // Objects for the background setting class.
    private JButton setBlankButton;
    private JComboBox comboBoxScale;
    private JButton loadImageButton;
    private JCheckBox iconCheckBox;
    private JPanel pnlBackgroundColor;

    // Objects for the text-style class.
    private JList textEffectList;
    private JTextField effectSizeText;
    private JTextField fontSizeText;
    private JTextField familiyFontTextField;
    private JComboBox styleComboBox;

    // Objects for the styles and rules class.
    private JList stylesList;
    private JTextArea textAreaRules;
    private JButton setStyleToSelectedButton;
    private JButton clearRuleButton;

    private JList compList;

    private JPanel pnlEffectColor;
    private JPanel extraTab;
    private JScrollPane componentPane;
    public JScrollPane extraContent;
    private JPanel componentPanel;
    private JScrollPane compScrollPane;
    private JTextField textAlpha;
    private JButton alphaButton;
    private JButton deleteButton;
    private ButtonGroup borderType;
    private JFileChooser fileChooser;

    private ResourceBundle localization;
    private Locale locale;

    boolean newHierarchy = false;
    boolean newOrDelete  = false;

    JTextField[] textFields = new JTextField[]{size_XTextField, size_YTextField, posXTextField, posYTextField, nameTextField, styleClassTextField};
    JCheckBox[] stateBoxes = new JCheckBox[]{defaultCheckBox, hoverCheckBox, disableCheckBox, downCheckBox, selectedCheckBox, deSelectedCheckBox,};
    JRadioButton[] alignment = new JRadioButton[]{leftRadioAlignment, centerRadioAlignment, rightRadioAlignment, bottomRadioAlignment, centerRadioVerAlignment, topRadioAlignment};
    JTextField[] padding = new JTextField[]{leftTextField, rightTextField, topTextField, bottomTextField};

    WorkBench workbench;

    private Queue<UpdateableProperties> updateableProps = new LinkedList<UpdateableProperties>();

    public PropertiesFrame() {

        setTitle("Component properties");
        setLayout(new BorderLayout());

        getContentPane().add(main_panel, BorderLayout.NORTH);

        setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);

        addWindowListener(new WindowAdapter() {
            public void windowClosing(WindowEvent e) {
                setVisible(false);
            }
        });

        setVisible(true);

        updateableProps.add(new DefaultTextFields(textFields, elementField, parentField));
        updateableProps.add(new ComponentList(compScrollPane));

        updateableProps.add(new StateBoxes(stateBoxes));
        updateableProps.add(new StylesAndRules(stylesList, textAreaRules, setStyleToSelectedButton, clearRuleButton, deleteButton));
        updateableProps.add(new BackgroundSetting(setBlankButton, loadImageButton, comboBoxScale,
                                                  iconCheckBox, pnlBackgroundColor, textAlpha, alphaButton));
        updateableProps.add(new TextSetting(setTextField, alignment, padding, pnlTextColor, setLocalizedText, localeChooser));
        updateableProps.add(new TextStyleProp(textEffectList, effectSizeText, fontSizeText, familiyFontTextField,
                                              styleComboBox, pnlEffectColor, stateBoxes ));

        UpdateCont.get().setPropertiesFrame(this);

        pack();
        sendToTread();
    }


    public boolean getHierarchyChange() {
        return newHierarchy;
    }

    public void setHierarchyChange(boolean val) {
        newHierarchy = val;
    }

    public boolean isNewOrDeleted() {
        return newOrDelete;
    }

    public void setNewOrDelete(boolean val) {
        newOrDelete = val;
    }

    private void createUIComponents() {

        String optImageScale[] = {"CENTER_XY", "CENTER_X", "CENTER_Y",
                                  "SCALE_XY", "SCALE_X", "SCALE_Y",
                                  "FRAME_XY", "FRAME_X", "FRAME_Y"};

        comboBoxScale = new JComboBox(optImageScale);
        comboBoxScale.setSelectedIndex(3);

        String optFontStyle[] = {"plain", "bold", "italic", "bolditalic"};

        styleComboBox = new JComboBox(optFontStyle);

        styleComboBox.setForeground(Color.black);
        styleComboBox.setBackground(Color.white);

        String optLocale[] = {"NO", "EN", "ZH"};

        localeChooser = new JComboBox(optLocale);
    }

    public void updateProperties(WorkBench workBench) throws InvocationTargetException, InterruptedException {

        // If there is no focused workbench we do nothing.
        if (workBench == null) return;

        if (workBench != this.workbench) {
            this.workbench = workBench;
        }

        // Get all components from the currently active workbench
        final Set< PeelComponent > allComponents      = workbench.getBui().getAllComponents();
        final Set< PeelComponent > selectedComponents = workbench.getBui().getSelections();

        PeelComponent selectedComp = null;

        // Set the main selected component.
        if (!selectedComponents.isEmpty()) {
            selectedComp = (PeelComponent)selectedComponents.toArray()[0];
        }

        // The update loop for the component properties layout and updating of components and stylesheets.
        for (UpdateableProperties anUpdateableProp : updateableProps) {

            anUpdateableProp.needUpdate( workBench, allComponents, selectedComponents, selectedComp, PropertiesFrame.this );

            if (anUpdateableProp.wantUpdate()) {

                final UpdateableProperties temp = anUpdateableProp;

                // Updating of swing layout is sent to the swing thread.
                SwingUtilities.invokeAndWait( new Runnable() {

                    public void run() {
                        temp.update();
                        temp.updateDone();
                    }
                });
            }

            if (anUpdateableProp.hasNewChange()) {

                if (selectedComp == null && !(anUpdateableProp instanceof StylesAndRules)
                                         && !(anUpdateableProp instanceof ComponentList)) return;

                final PeelComponent component = selectedComp;
                final UpdateableProperties temp = anUpdateableProp;

                // Updating of components and stylesheets is sent to the workbench thread.
                workBench.getBui().execute(new WorkBench.Task() {
                    public void run() {
                        temp.applyChange(component, PropertiesFrame.this);
                        temp.changeApplied();
                    }
                });
            }
        }
        SwingUtilities.invokeAndWait( new Runnable() {

            public void run() {
                pack();
            }
        });
    }

    public void applyToSelectedStates(PeelComponent component, Object value) {

        for (int i = 0; i < stateBoxes.length; i++) {
            if (!stateBoxes[i].isSelected()) {
                continue;
            }

            get().updateStyleClassRules( component, (String)stateBoxes[i].getClientProperty( "state" ), value );
        }
    }

    // Thread for the components property window.
    private void sendToTread() {

        new Thread("PropertyWindowUpdater") {
            @Override
            public void run() {
                try {
                    while ( true ) {
                        updateProperties( UpdateCont.get().getFocusedWorkBench() );
                        Thread.sleep( 10 );

                    }
                } catch (Exception e) {
                    System.out.println("Property box crashed, here are the details");
                    e.printStackTrace();
                }
            }
        }.start();
    }
}


